package mysgoog.util;

import mysgoog.bot.Config;
import mysgoog.gtp.Color;
import mysgoog.gtp.Vertex;
import mysgoog.pattern.Storage.ValueTriple;
import mysgoog.pattern.Storage.VertexValue;
/**
* @author Fu, Zhongyang
*/
public class BoardUtil {
	private static final int LEFTRIGHT = 0;
	private static final int UPDOWN = 1;
	private static final int LRUD = 2;
	
	public static VertexValue changeVertex(VertexValue vertexValue, int x, int y){
		return new VertexValue(new Vertex(vertexValue.vertex.x + x, vertexValue.vertex.y + y), vertexValue.value);
	}
	
	public static Vertex changeVertex(Vertex vertex, int x, int y){
		return new Vertex(vertex.x + x, vertex.y + y);
	}
	
	public static Vertex rotateVertex(Vertex v, int boardSize, int degree){
		switch (degree){
			case 0:
				return new Vertex(v.x, v.y);
			case 90:
				return new Vertex(v.y, boardSize - 1 - v.x);
			case 180:
				return new Vertex(boardSize - 1 - v.x, boardSize - 1 - v.y);
			case 270:
				return new Vertex(boardSize - 1 - v.y, v.x);
		}
		return null;
	}

	
	public static VertexValue rotateVertex(VertexValue v, int boardSize, int degree){
		switch (degree){
			case 0:
				return new VertexValue(new Vertex(v.vertex.x, v.vertex.y), v.value);
			case 90:
				return new VertexValue(new Vertex(v.vertex.y, boardSize - 1 - v.vertex.x), v.value);
			case 180:
				return new VertexValue(new Vertex(boardSize - 1 - v.vertex.x, boardSize - 1 - v.vertex.y), v.value);
			case 270:
				return new VertexValue(new Vertex(boardSize - 1 - v.vertex.y, v.vertex.x), v.value);
		}
		return null;
	}
	
	public static char parseColor(Color color, Color player){
		char ans;		
		if (!color.isFilled()) ans = '.';
		else if (color == player) ans = 'O';
		else ans = 'X';
		return ans;
	}
	
	//get the sub board according to a given position vector
	public static Color[] getSubBoard(Color[] board, int[] pos){
		Color[] ans = new Color[pos.length];
		for (int i = 0; i < pos.length; i++)
			ans[i] = board[pos[i]];			
		return ans;
	}
	
	public static String getSubBoardString(Color[] board, int[] pos, Color player){
		String ans = new String();
		for (int i = 0; i < pos.length; i++){
			if (!Config.getEmptyBoard().inBoard(pos[i])) ans += "|";
			ans += parseColor(board[pos[i]], player);
		}
		return ans;
	}
	
	//get the sub board position vector.
	//(x,y) up-left corner of the sub board
	//row&column rows and columns of the sub board
	public static Color[] getSubBoard(int x, int y, int row, int column, Color[] board){
		Color[] ans = new Color[row * column];
		int count = 0;
		for (int i = x; i < x + row; i++){
			for (int j = y; j < y + column; j++){
				ans[count] = board[Config.getEmptyBoard().makePos(i, j)];
			}
		}
		return ans;
	}
	
	//get the sub board position vector.
	//(x,y) up-left corner of the sub board
	//row&column rows and columns of the sub board
	public static String getSubBoardString(int x, int y, int row, int column, Color[] board, Color player){
		String ans = new String();
		int count = 0;
		for (int i = x; i < x + row; i++){
			for (int j = y; j < y + column; j++){
				int pos = Config.getEmptyBoard().makePos(i, j);
				if (!Config.getEmptyBoard().inBoard(i, j)) ans += '|';
				else ans += parseColor(board[pos], player);
			}
		}
		return ans;
	}
	
	public static int[] getSubBoard(int x, int y, int row, int column){
		int[] ans = new int[row * column];
		int count = 0;
		for (int i = x; i < x + row; i++){
			for (int j = y; j < y + column; j++){
				ans[count] = Config.getEmptyBoard().makePos(i, j);
			}
		}
		return ans;
	}
	
	//rotate board
	//row&column is the row&column of the input board
	//degree is clockwise rotate, can be 90, 180, 270
	public static Color[] rotateBoard(int row, int column, Color[] board, int degree){
		Color[] ans = new Color[row * column];
		switch (degree){
			case 90:
				for (int i = 0; i < column; i++){
					for (int j = 0; j < row; j++){
						ans[i * row + j] = board[(row - 1 - j) * column + i];
					}
				}
				return ans;
			case 180:
				return symBoard(row, column, board, 2);
			case 270:
				for (int i = 0; i < column; i++){
					for (int j = 0; j < row; j++){
						ans[i * row + j] = board[j * column + (column - 1 - i)];
					}
				}
				return ans;
		}
		return null;
	}
	
	//direction can be 0,1,2 
	//0 is left-right sym, or LEFTRIGHT
	//1 is up-down sym, or UPDOWN
	//2 is for both left-right and up-down sym, or LRUD
	//row&column is the r&c of input board
	public static Color[] symBoard(int row, int column, Color[] board, int direction){
		Color[] ans = new Color[row * column];		
		switch (direction){
			case LEFTRIGHT:
				for (int i = 0; i < row; i++){
					for (int j = 0; j < column; j++){
						ans[i * column + j] = board[i * column + (column - 1 - j)];
					}
				}
				return ans;
			case UPDOWN:
				for (int i = 0; i < row; i++){
					for (int j = 0; j < column; j++){
						ans[i * column + j] = board[(row - 1 - i) * column + j];
					}
				}
				return ans;
			case LRUD:
				for (int i = 0; i < row; i++){
					for (int j = 0; j < column; j++){
						ans[i * column + j] = board[(row - 1 - i) * column + (column - 1 - j)];
					}
				}
				return ans;
				
		}
		return null;	
	}

	
	//rotate board
	//row&column is the r&c of input board
	//degree is clockwise rotate, can be 90, 180, 270
	public static int[] rotateBoard(int row, int column, int[] board, int degree){
		int[] ans = new int[row * column];
		switch (degree){
			case 90:
				for (int i = 0; i < column; i++){
					for (int j = 0; j < row; j++){
						ans[i * row + j] = board[(row - 1 - j) * column + i];
					}
				}
				return ans;
			case 180:
				return symBoard(row, column, board, 2);
			case 270:
				for (int i = 0; i < column; i++){
					for (int j = 0; j < row; j++){
						ans[i * row + j] = board[j * column + (column - 1 - i)];
					}
				}
				return ans;
		}
		return null;
	}
	
	//direction can be 0,1,2 
	//0 is left-right sym, or LEFTRIGHT
	//1 is up-down sym, or UPDOWN
	//2 is for both left-right and up-down sym, or LRUD
	//row&column is the r&c of input board
	public static int[] symBoard(int row, int column, int[] board, int direction){
		int[] ans = new int[row * column];		
		switch (direction){
			case LEFTRIGHT:
				for (int i = 0; i < row; i++){
					for (int j = 0; j < column; j++){
						ans[i * column + j] = board[i * column + (column - 1 - j)];
					}
				}
				return ans;
			case UPDOWN:
				for (int i = 0; i < row; i++){
					for (int j = 0; j < column; j++){
						ans[i * column + j] = board[(row - 1 - i) * column + j];
					}
				}
				return ans;
			case LRUD:
				for (int i = 0; i < row; i++){
					for (int j = 0; j < column; j++){
						ans[i * column + j] = board[(row - 1 - i) * column + (column - 1 - j)];
					}
				}
				return ans;
				
		}
		return null;	
	}
	
	
	// pattern use the following model to store
	//      #  ? - don't care
	//		#  . - empty
	//		#  X - opposite color of O
	//		#  O - color of dragon looking for connection
	//		#  x - X or empty
	//		#  o - O or empty
	public static boolean patternMatch(Color[] board, String pattern, Color player){
		if (board.length != pattern.length()) return false;
		for (int i = 0; i < board.length; i++){
			if (pattern.charAt(i) == '?') continue;
			if (board[i] == Color.WHITE){
				if ((pattern.charAt(i) == 'O') || (pattern.charAt(i) == 'o')) continue;
				return false;
			}
			else if (board[i] == Color.BLACK){
				if ((pattern.charAt(i) == 'X') || (pattern.charAt(i) == 'x')) continue;
				return false;
			}
			else{
				if ((pattern.charAt(i) == '.') || (pattern.charAt(i) == 'o') || (pattern.charAt(i) == 'x')) continue;
				return false;
			}			
		}
		return true;
	}

}
